/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdlib.h>
#include <string.h>
#include "../include/pinyinime.h"
#include "../include/dicttrie.h"
#include "../include/matrixsearch.h"
#include "../include/spellingtrie.h"

#ifdef __cplusplus
extern "C" {
#endif

  using namespace ime_pinyin;

  // The maximum number of the prediction items.
  static const size_t kMaxPredictNum = 500;

  static const size_t kMaxPinyingSplit = 500;
  static char pinyin_split_buf[kMaxPinyingSplit];
  static const size_t kMaxPinyingLength = 6;

  // Used to search Pinyin string and give the best candidate.
  MatrixSearch* matrix_search = NULL;

  char16 predict_buf[kMaxPredictNum][kMaxPredictSize + 1];

  bool im_open_decoder(const char *fn_sys_dict, const char *fn_usr_dict) {
    if (NULL != matrix_search)
      delete matrix_search;

    matrix_search = new MatrixSearch();
    if (NULL == matrix_search) {
      return false;
    }

    return matrix_search->init(fn_sys_dict, fn_usr_dict);
  }

  bool im_open_decoder_fd(int sys_fd, long start_offset, long length,
                          const char *fn_usr_dict) {
    if (NULL != matrix_search)
      delete matrix_search;

    matrix_search = new MatrixSearch();
    if (NULL == matrix_search)
      return false;

    return matrix_search->init_fd(sys_fd, start_offset, length, fn_usr_dict);
  }

  void im_close_decoder() {
    if (NULL != matrix_search) {
      matrix_search->close();
      delete matrix_search;
    }
    matrix_search = NULL;
  }

  void im_set_max_lens(size_t max_sps_len, size_t max_hzs_len) {
    if (NULL != matrix_search) {
      matrix_search->set_max_lens(max_sps_len, max_hzs_len);
    }
  }

  void im_flush_cache() {
    if (NULL != matrix_search)
      matrix_search->flush_cache();
  }

  // To be updated.
  size_t im_search(const char* pybuf, size_t pylen, size_t pyfixed_len) {
    if (NULL == matrix_search)
      return 0;

    matrix_search->search(pybuf, pylen, pyfixed_len);
    return matrix_search->get_candidate_num();
  }

  size_t im_delsearch(size_t pos, bool is_pos_in_splid,
                      bool clear_fixed_this_step) {
    if (NULL == matrix_search)
      return 0;
    matrix_search->delsearch(pos, is_pos_in_splid, clear_fixed_this_step);
    return matrix_search->get_candidate_num();
  }

  void im_reset_search() {
    if (NULL == matrix_search)
      return;

    matrix_search->reset_search();
  }

  // To be removed
  size_t im_add_letter(char ch) {
    return 0;
  }

  const char* im_get_sps_str(size_t *decoded_len) {
    if (NULL == matrix_search)
      return NULL;

    return matrix_search->get_pystr(decoded_len);
  }

  char16* im_get_candidate(size_t cand_id, char16* cand_str,
                        size_t max_len) {
    if (NULL == matrix_search)
      return NULL;

    return matrix_search->get_candidate(cand_id, cand_str, max_len);
  }

  char* im_get_candidate_pinyin(size_t can_id, char* cand_pinyin_str,
  						   	size_t max_len) {
	  if (NULL == matrix_search)
		  return NULL;

	  char* ret = matrix_search->get_candidate_pinyin_under_bellpad( can_id, cand_pinyin_str, max_len );
	  return ret;
  }

  size_t im_get_spl_start_pos(const uint16 *&spl_start) {
    if (NULL == matrix_search)
      return 0;

    return matrix_search->get_spl_start(spl_start);
  }

  const char* im_get_pinyin_from_keys( const char* key )
  {
	if (NULL== key){
		return NULL;
	}
  
	size_t key_length = strlen( key );
	char key_input[kMaxPinyingLength+1];
	memset( key_input, 0, kMaxPinyingLength+1 );

	//we begin support the pinyin for the candidate select only from the number
	size_t num_begin = 0;
	for( num_begin=0; num_begin<key_length; ++num_begin )
	{
		if( true==matrix_search->is_number(key[num_begin]) )
			break;
	}
	key_length = key_length - num_begin;

	if( key_length>kMaxPinyingLength )
		key_length = kMaxPinyingLength;
	
	memset( pinyin_split_buf, 0, kMaxPinyingSplit );

	size_t buf_used = 0;
	for( size_t  i=1; i<key_length+1; ++i )
	{
		strncpy( key_input, &key[num_begin], i );
		key_input[i+1] = '\0';

		int count = im_get_pinyin_from_keys_core( key_input, &pinyin_split_buf[buf_used], kMaxPinyingSplit-buf_used );
		
		if( count>0 )
			buf_used = strlen( pinyin_split_buf );
		if( buf_used>=kMaxPinyingSplit )
		{
			pinyin_split_buf[kMaxPinyingSplit] = '\0';
			break;
		}
		pinyin_split_buf[buf_used] = '\0';
	}

//	size_t ret = matrix_search->sort_pinyin_by_sorce( pinyin_split_buf, buf_used );
//	if( ((size_t)(-1))==ret )
//		return NULL;
	
	return pinyin_split_buf;
  }

  size_t im_get_pinyin_from_keys_core( const char*keys, char* outPinyin, uint16 outBufSize )
  {
	if (NULL == matrix_search)
		  return 0;
	
	return matrix_search->get_pinyin_under_bellpad( keys, outPinyin, outBufSize );
  }

  size_t im_choose(size_t choice_id) {
    if (NULL == matrix_search)
      return 0;

    return matrix_search->choose(choice_id);
  }

  size_t im_cancel_last_choice() {
    if (NULL == matrix_search)
      return 0;

    return matrix_search->cancel_last_choice();
  }

  size_t im_get_fixed_len() {
    if (NULL == matrix_search)
      return 0;

    return matrix_search->get_fixedlen();
  }

  // To be removed
  bool im_cancel_input() {
    return true;
  }


  size_t im_get_predicts(const char16 *his_buf,
                         char16 (*&pre_buf)[kMaxPredictSize + 1]) {
    if (NULL == his_buf)
      return 0;

    size_t fixed_len = utf16_strlen(his_buf);
    const char16 *fixed_ptr = his_buf;
    if (fixed_len > kMaxPredictSize) {
      fixed_ptr += fixed_len - kMaxPredictSize;
      fixed_len = kMaxPredictSize;
    }

    pre_buf = predict_buf;
    return matrix_search->get_predicts(his_buf, pre_buf, kMaxPredictNum);
  }

  void im_enable_shm_as_szm(bool enable) {
    SpellingTrie &spl_trie = SpellingTrie::get_instance();
    spl_trie.szm_enable_shm(enable);
  }

  void im_enable_ym_as_szm(bool enable) {
    SpellingTrie &spl_trie = SpellingTrie::get_instance();
    spl_trie.szm_enable_ym(enable);
  }

#ifdef __cplusplus
}
#endif
